import 'dart:async';
import 'dart:convert';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:zhibao_flutter/api/user/user_entity.dart';
import 'package:zhibao_flutter/api/user/user_view_model.dart';
import 'package:zhibao_flutter/util/check/check.dart';
import 'package:zhibao_flutter/util/config/app_config.dart';
import 'package:zhibao_flutter/util/data/q1_data.dart';
import 'package:zhibao_flutter/util/func/log.dart';
import 'package:zhibao_flutter/util/func/sp_util.dart';
import 'package:zhibao_flutter/util/func/tips_util.dart';
import 'package:zhibao_flutter/widget/view/hud_view.dart';
import 'package:zhibao_flutter/zone.dart';

import 'api.dart';
import 'base_response_model.dart';

typedef OnData(t);
typedef OnError = Function(int code);

/*
* 请求类型
* 
* @param post 用于提交表单
* @param get 用于获取信息
* @param put 用于修改信息
* @param delete 用于删除
* @param getPin 用于拼接形式get请求
* @param file 用于上传文件
* @param oss 用于阿里对象存储
* @param html 用户获取链接的Html代码
* @param patch 补丁
*
* */
enum ReqType { post, get, put, del, getPin, file, html, patch }

class BaseRequest {
  String? url() => null;

  bool retJson() => true;

  Duration? cacheTime() => null;

  bool needLogin() => false;

  Map<String, dynamic> toJson() => {};

  Future<dynamic> sendApiAction(
    BuildContext? context, {
    ReqType reqType = ReqType.get,
    String? hud = '加载中...',
    OnData? onStore,
    OnError? onErrorInApi,
    ProgressCallback? onReceiveProgress,
    ProgressCallback? onSendProgress,
    int second = 10,
    bool isFetchResult = true,
  }) async {
    /// Default text to localization.
    if(hud == "加载中..."){
      hud = 'loading'.tr;
    }
    bool isFetchStoreData = false;
    String storeApiKey = "";
    if (reqType != ReqType.file) {
      storeApiKey = "${Q1Data.id}${url()}${json.encode(this.toJson())}";

      LogUtil.d(
          "【sendApiAction】【Store】【${storeApiKey}】onStore != null::${onStore != null}");

      /// Need fetch store data.
      if (onStore != null) {
        try {
          String? storeValue = SpUtil().get(storeApiKey);
          LogUtil.d("【sendApiAction】【Store】【storeValue】$storeValue");

          if (strNoEmpty(storeValue) && storeValue != "null") {
            onStore(json.decode(storeValue!));
            LogUtil.d(
                "【sendApiAction】【Store】【${storeApiKey}】Send Data success");
            isFetchStoreData = true;
          }
        } catch (e) {
          LogUtil.d("fetch apk store data error ${e.toString()}");
        }
      }
    }
    try {
      /// Net work check
      /// Check is have open network.
      var connectivityResult = await (Connectivity().checkConnectivity());
      if (connectivityResult == ConnectivityResult.none) {
        LogUtil.d("当前无网络，直接抛出异常");
        throw ResponseModel.fromError(TipsUtil.netError, null, url());
      }

      if (context != null && !isFetchStoreData && hud != null) {
        HudView.show(context, msg: hud);
      }

      var result = await api(url()!, reqType, retJson(), this, cacheTime(),
          onReceiveProgress, onSendProgress);

      if (context != null) {
        await Future.delayed(const Duration(milliseconds: 500))
            .then((value) => HudView.dismiss());
      }

      if (reqType == ReqType.html) return result;

      if (result == null) {
        throw ResponseModel.fromError(AppConfig.timeOutStr, null, url());
      } else if (result['code'] == 5 ||
          result['code'] == 6 ||
          result['code'] == 401) {
        debugPrint('登录失效 去重新登录');
        // userViewModel.loginOff();
        userViewModel.loginOut();
        if (onErrorInApi != null) onErrorInApi(result['code']);
        final tipMsg = result is Map &&
                result.containsKey('msg') &&
                strNoEmpty(result['msg'])
            ? result['msg']
            : '请重新登录';
        throw ResponseModel.fromError(tipMsg, null, url());
      } else if (result['code'] == '1' || result['code'] == 1) {
        if (result['msg'] == '账号不存在或被删除') {
          // Q1Data.clean();
        }
        if (onErrorInApi != null) onErrorInApi(1);
        throw ResponseModel.fromError(result['msg'], 1, url());
      } else if (result['status'] == 10039) {
        if (onErrorInApi != null) onErrorInApi(10039);
        throw ResponseModel.fromError(result['msg'], 10039, url());
      } else if (result['code'] == 10) {
        if (onErrorInApi != null) onErrorInApi(10);
        throw ResponseModel.fromError(result['msg'], 10, url());
      } else if (result['code'] == 600 ||
          result['code'] == 403 ||
          result['code'] == 802) {
        if (onErrorInApi != null)
          onErrorInApi(int.parse(result['code'].toString()));
        throw ResponseModel.fromError(
          result['msg'],
          int.parse(result['code'].toString()),
          url(),
        );
      } else if (result['code'] == 707) {
        /// {"code":707,"msg":"系统维护中",
        /// "payload":{"maintenance_time":"2018-10-30 21:04:04 到 2018-10-31 21:04:13",
        /// "maintenance_info":"1、用户体验优化！\n2、对部分算法进行优化调整；"},
        /// "path":"","method":""}
        if (onErrorInApi != null) onErrorInApi(707);
        throw ResponseModel.fromError('系统维护中', 707, url());
      }
      if (url()!.contains('oss-cn-') ||
          url()!.contains('v1/task/treasure_box') ||
          url()!.contains('/v1/task/ad/reward')) {
        return result;
      } else if (result['code'] == '2' || result['code'] == 2) {
        if (onErrorInApi != null) onErrorInApi(2);
        throw ResponseModel.fromError('no', 2, url());
        // Tower 任务: 如果两个设备登录同一账号的时候，另外一个账号退到登录页面 ( https://tower.im/teams/995083/todos/817 )
        /// Handle [isFetchResult] in new version.
      } else if (!isFetchResult) {
        if (onStore != null) {
          SpUtil().setString(storeApiKey, json.encode(result));
        }
        return result;
      } else if (result['code'] != 0 && result['code'] != 200) {
        if (onErrorInApi != null)
          onErrorInApi(int.parse('${result["code"] ?? 0}'));
        throw ResponseModel.fromError(
            result["msg"] ?? result['message'], result["code"], url());
      }
      if (url()!.contains('user/sendSms')) {
        return result['msg'] ?? result['message'];
      }

      if (Map.from(result).containsKey('data')) {
        if (onStore != null) {
          SpUtil().setString(storeApiKey, json.encode(result['data']));
        }
        return result['data'];
      } else if (Map.from(result).containsKey('Data')) {
        if (onStore != null) {
          SpUtil().setString(storeApiKey, json.encode(result["Data"]));
        }
        return result["Data"];
      } else if (Map.from(result).containsKey('payload')) {
        if (onStore != null) {
          SpUtil().setString(storeApiKey, json.encode(result['payload']));
        }
        return result['payload'];
      } else {
        if (onStore != null) {
          SpUtil().setString(storeApiKey, json.encode(result));
        }
        return result;
      }
    } catch (e) {
      if (context != null) {
        await Future.delayed(const Duration(milliseconds: 500))
            .then((value) => HudView.dismiss());
      }
      throw e;
    }
  }
}

class AuthError extends Error {
  @override
  String toString() {
    return '登录状态已失效';
  }
}
